#!/usr/bin/evn python
# -*- coding:utf-8 -*-


import sys, os

sys.path.append('..')

import json
import time
import selectors
import socket

PORT = 8390


class server:
    def __init__(self):
        self._sock = socket.socket()
        self._selector = selectors.DefaultSelector()

    def start(self, **kw):
        self.running = True
        sock = self._sock
        sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        sock.setblocking(0)
        sock.bind(('', PORT))
        sock.listen(100)
        selector = self._selector
        self.add_handler(sock.fileno(), self._accept, selectors.EVENT_READ)
        while True:
            events = selector.select(1)
            for key, event in events:
                print(key)
                print(event)
                handler, data = key.data
                if data:
                    handler(**data)
                else:
                    handler()

    def add_handler(self, fd, handler, event, data=None):
        self._selector.register(fd, event, (handler, data))

    def remove_handler(self, fd):
        self._selector.unregister(fd)

    def _accept(self):
        for i in range(100):
            try:
                conn, address = self._sock.accept()
            except OSError:
                break
            else:
                conn.setblocking(0)
                fd = conn.fileno()
                self.add_handler(fd, self._read, selectors.EVENT_READ, {'conn': conn})

    def _read(self, conn):
        fd = conn.fileno()
        self.remove_handler(fd)
        try:
            data = conn.recv(65535)
        except:
            conn.close()
            raise
        else:
            self.add_handler(fd, self._write, selectors.EVENT_WRITE, {'conn': conn, 'data': data})

    def _write(self, conn, data):
        fd = conn.fileno()
        self.remove_handler(fd)
        try:
            response = self._prep(data)
            if isinstance(response, bytes):
                conn.sendall(response)
            else:
                conn.sendall(response.encode('utf-8'))
        finally:
            conn.close()

    def get_url_config(self, url):
        """通过url获取定义在settings中的配置信息"""
        from settings import URL_LIST
        for config in URL_LIST:
            mode = config["mode"]
            if mode == "exact" and url == config["url"]:
                return config

            if mode == "fuzz" and url.startswith(config["url"]):
                return config

    def _prep(self, data):
        """
        从写该方法，处理返回值
        :param data: 包含url和后端真正的返回值
        :return:
        """
        if isinstance(data, bytes):
            key = data.index(b":")
            url = data[:key].decode("utf-8")
            Ox0Data = data[key + 1:]
        else:
            url, Ox0Data = data.split(':', 1)
        print(Ox0Data)
        print(url)

        config = self.get_url_config(url)

        print(config)
        if not config:
            print("该url：{}未找到对应的配置，将直接返回服务端的结果".format(url))
            return Ox0Data
        else:

            # 处理配置中其他信息,比如说延迟返回
            if "delay" in config:
                delay = config['delay']
                time.sleep(delay)

            data = Ox0Data.decode("utf-8")
            response = self.getResponse(data, config)
            if isinstance(response, dict):
                response = json.dumps(response)
            return response

    def getResponse(self, data, config):
        """根据config,更改fiddler传过来的data,data是真正的服务端返回的数据"""
        import copy
        tmpData = copy.deepcopy(data)
        try:
            data = json.loads(data)

            action = config['action'] if "action" in config else {}
            for actionKey in action:
                actionValue = action[actionKey]

                ks = actionKey.split(".")  # 代表一个一个单词 如data.memberLevel

                if len(ks) > 2:
                    raise Exception("抱歉,暂时只支持最多2层的替换")

                if len(ks) == 1:
                    data[actionKey] = actionValue
                elif len(ks) == 2:
                    a, b = ks
                    data[a][b] = actionValue
            return data

        except Exception as e:
            print("ERROR:{}".format(str(e)))
            return tmpData


if __name__ == "__main__":
    mockserver = server()
    print('mock server start!')
    mockserver.start()
